import reportlab.platypus as ppus
from reportlab.lib.styles import getSampleStyleSheet
from reportlab.lib.pagesizes import A4, letter
from reportlab.lib import colors
import reportlab.lib.units
import inspect
from tagsupport import TagBuilder

def build_plist(attrs, func):
	"""Takes a function and a list of attributes and maps the attributes to the function parameters"""
	args = []
	for i in inspect.getargs(func.im_func.func_code)[0]:
		if not i == 'self':
			if attrs.has_key(i):
				args.append(attrs[i])
			else:
				args.append(None)
	return args
	
class DocumentObject(object):
	def __init__(self):
		object.__init__(self)
		self._content = []
		
	def append(self, cont):
		self._content.append(cont.content())
		return self
		
class UnknownTag(DocumentObject):
	def __init__(self, tag, attrs):
		DocumentObject.__init__(self)
		self.name = tag
		self.attrs = attrs
		
	def append(self,cont):
		self._content.append(cont)
		return self
				
	def __str__(self):
		return self.content()
		
	def content(self):
		rstr = TagBuilder.rebuild_tag(self.name, self.attrs)
		for i in self._content:
			rstr+=str(i)
		rstr+=TagBuilder.rebuild_closure(self.name)
		return rstr
		
class Line(DocumentObject):
	"""Class to rappresent an horizontal line"""    
	class _LineImpl(ppus.Flowable):
		"""Internal hidden implementation of the line"""
		def __init__(self, w, h):
			ppus.Flowable.__init__(self)
			self.w = w*Document.unit
			self.h = h/10*Document.unit
			self.rw = w
			self.rh = h/10*Document.unit+5

		def __repr__(self):
        		return "<hr width=%s size=%s>" % (self.w, self.h)
	
		def split(self, availWidth, availHeight):
			return []

		def wrap(self, availWidth, availHeight):
			return ( self.w, self.h )

		def draw(self):
			self.canv.setLineWidth ( self.h )
     			self.canv.line ( 0 , 0, self.w, 0 )
			
	def __init__(self, width=None, height=None):
		DocumentObject.__init__(self)
		if width == None:
			width = 160
		if height == None:
			height = 1
		self._impl = self._LineImpl(int(width), int(height))
		
	def content(self):
		return (self._impl, ppus.Spacer(self._impl.rw, self._impl.rh))
		
class Image(ppus.Image, DocumentObject):
	"""Class to rappresent an image"""
	def __init__(self, src, align=None, width=None, height=None):
		DocumentObject.__init__(self)
		if width:
			width = int(width)*Document.unit
		if height:
			height = int(height)*Document.unit
		ppus.Image.__init__(self, src, width, height)
		if align:
			self.hAlign = align.upper()
		else:
			self.hAlin = 'CENTER'
			
	def content(self):
		return self
			
class Text(DocumentObject):
	"""Class to handle a text block"""
	def __init__(self, align=None):
		self.attrs = {}
		if align:
			self.attrs['align'] = align
		self.text = ''
			
	def append(self, text):
		self.text += str(text)
		return self
		
	def content(self):
		self.text = TagBuilder.rebuild_tag('para',self.attrs,TagBuilder.CLOSABLE) + self.text + TagBuilder.rebuild_closure('para',TagBuilder.CLOSABLE)
		return ppus.Paragraph(self.text, getSampleStyleSheet()["Normal"])
		
class Space(ppus.Spacer, DocumentObject):
	"""Class to handle an empty space"""
	def __init__(self, width, height):
		ppus.Spacer.__init__(self, int(width)/10*Document.unit, int(height)*Document.unit)
		DocumentObject.__init__(self)
		
	def content(self):
		return self

class TableRow(DocumentObject):
	def __init__(self, size=None):
		DocumentObject.__init__(self)
		if size:
			self.size = int(size)*Document.unit
		else:
			self.size = None
			
	def content(self):
		return self
		
	def internals(self):
		return self._content
			
class TableCel(DocumentObject):
	def __init__(self, celcontent, align=None, bgcolor=None, size=None, valign=None, border=None):
		DocumentObject.__init__(self)
		if size:
			self.size = int(size)*Document.unit
		else:
			self.size = None
			
		if bgcolor:
			self.hexcolor = colors.HexColor(bgcolor)
		else:
			self.hexcolor = colors.white
		
		if align == None:
			self.align = 'LEFT'
		else:
			self.align = align.upper()
			
		if valign == None:
			self.valign = 'TOP'
		else:
			self.valign = valign.upper()

		if border:
			self.border = int(border)
		else:
			self.border = 0
			
	def content(self):
		return self
	
	def internals(self):
		return self._content
		
class Table(DocumentObject):
	"""Class to handle a table"""
	def __init__(self, align=None, border=None, color=None):
		DocumentObject.__init__(self)
		if align == None:
			align = 'CENTER'
		if border == None:
			border = 0
		if color:
			self._dcolor = color
		else:
			self._dcolor = colors.white

		self._border = int(border)
		self._align = align.upper()
		
	def content(self):
		rowsizes = []
		colsizes = []		
		table = []
		tablestyle = ppus.TableStyle()
		coli = rowi = 0
		
		for row in self._content:
			table.append([])
			if not isinstance(row,TableRow):
				raise Exception,"Found something which is of type: "+str(type(row))+" instead of TableRow inside a Table"
			if row.size:
				rowsizes.append(row.size)
			coli = 0
			for col in row.internals():
				if col.size:
					colsizes.append(col.size)
				tablestyle.add('BACKGROUND', (coli, rowi), (coli, rowi), col.hexcolor)
				tablestyle.add('ALIGN', (coli, rowi), (coli, rowi), col.align)
				tablestyle.add('VALIGN', (coli, rowi), (coli, rowi), col.valign)
				if col.border:
					tablestyle.add('BOX', (coli, rowi), (coli, rowi), col.border/10*Document.unit, colors.black)
				celcontent = []
				for i in col.internals():
					celcontent.append(i)
				if len(celcontent) > 1: table[-1].append(celcontent)
				elif len(celcontent) == 1: table[-1].append(celcontent[0])
				else: table[-1].append('')
				coli+=1
			rowi+=1
			
		if self._border:
			tablestyle.add('BOX', (0,0), (-1, -1), int(self._border)/10*Document.unit, colors.black)
			tablestyle.add('INNERGRID', (0,0), (-1,-1), int(self._border)/10*Document.unit, colors.black)
		
		if not len(colsizes):
			colsizes = None
		if not len(rowsizes):
			rowsizes = None	
		
		return ppus.Table(table, colsizes, rowsizes, tablestyle)
	
class NewPage(ppus.PageBreak):
	def __init__(self):
		ppus.PageBreak.__init__(self)
		
	def content(self):
		return self
		
class Document(DocumentObject):
	unit = reportlab.lib.units.mm
	def __init__(self, file, content=None):
		DocumentObject.__init__(self)
		self._file = file
		
		if content:
			self._content = content
		else:
			self._content = []

	def set_unit(unit):
		if unit == 'MM':
			Document.unit = reportlab.lib.units.mm
		elif unit == 'INCH':
			Document.unit = reportlab.lib.units.inch
		else:
			raise Exception,"Unknown unit type"
	set_unit = staticmethod(set_unit)
				
	def append(self, object):
 		if type(object) == type(Line()):
			self._content.extend(object.content())
		else:
			self._content.append(object.content())
		return self
			
	def end_of_page(self):
		self._content.append(ppus.PageBreak())
	
	def generate(self, psize='A4'):
		if psize=='LETTER':
			psize=letter
		elif psize=='A4':
			psize=A4
		else:
			raise Exception,"Unknown page size"
		self._document = ppus.SimpleDocTemplate(self._file, showBoundary=0, pagesize=psize)
		self._document.build(self._content)

		
class ObjectFactory(object):
	def Create(tag, attrs):
		if tag == 'para':
			return Text(*build_plist(attrs, Text.__init__))
		elif tag == 'space':
			return Space(*build_plist(attrs, Space.__init__))
		elif tag == 'img':
			return Image(*build_plist(attrs, Image.__init__))
		elif tag == 'tr':
			return TableRow(*build_plist(attrs, TableRow.__init__))
		elif tag == 'td':
			return TableCel(*build_plist(attrs, TableCel.__init__))
		elif tag == 'table':
			return Table(*build_plist(attrs, Table.__init__))
		elif tag == 'hr':
			return Line(*build_plist(attrs, Line.__init__))
		else:
			return UnknownTag(tag, attrs)
	Create = staticmethod(Create)
	
if __name__ == "__main__":
	doc = Document("prova.pdf")
	doc.append(Text().append('oooooooooooooooooooooooooooooooooooooooooooooooooooooooo'))
	doc.append(Text().append('ciao <i>pippo</i>'))
	doc.append(Space(10, 50))
	doc.append(Line(50))
	doc.append(Image('logo.jpg', 'LEFT', 100, 100))
	doc.append(Text(align='right').append('<font face="times" color="red" size=12>E PLUTO</font>'))
	
	t = Table()
	t.append(TableRow().append(TableCel(0)).append(TableCel(0)).append(TableCel(1)).append(TableCel(2)).append(TableCel(3)))
	t.append(TableRow().append(TableCel(0)).append(TableCel(0)).append(TableCel(1)).append(TableCel(2)).append(TableCel(3)))
	t.append(TableRow().append(TableCel(0)).append(TableCel(0)).append(TableCel(1)).append(TableCel(2)).append(TableCel(3)))
	t.append(TableRow().append(TableCel(0)).append(TableCel(0)).append(TableCel(1)).append(TableCel(2)).append(TableCel(3)))
	
	doc.append(t)
	doc.append(Image('logo.jpg'))
	
	doc.generate()